//Copyright  2015 Max "Shrinker" Wieden
//Refer to license for license details.

//contract:
//- if anything occours multiple times in a config file, the last entry supersedes the previous entries, unless the loading mechanism allows for array data, in which case all entries are respected
//- x {int y = 2;} is the same as int x.y = 2;

Tokens:
	Name              = FirstNameChar (FirstNameChar | Digit)*;
	FloatLiteral      = [['+', '-']] (BaseFloatLiteral [FloatExponent] | NumericLiteral FloatExponent);
	#FloatExponent    = ['E', 'e'] [['+', '-']] (Digit)+;
	IntLiteral        = HexLiteral | [['+', '-']] NumericLiteral;
	#CharContent      = '\\' ['r', 'n', 't', '\'', '\"', '\\'] | ~['\'', '\"', '\\'];
	StringLiteral     = //"abc" or (\""abc"" or \"#abc#" [...])
		'\"' (CharContent)* '\"' |
		'\\' //"abc" or (\""abc"" or \"#abc#" or \"(abc)" or ...)
		(
			"\"[" (~[']'])* (']')+ (~[']', '\"'] (~[']'])* (']')+)* '\"'
		|	"\"{" (~['}'])* ('}')+ (~['}', '\"'] (~['}'])* ('}')+)* '\"'
		|	"\"<" (~['>'])* ('>')+ (~['>', '\"'] (~['>'])* ('>')+)* '\"'
		|	"\"(" (~[')'])* (')')+ (~[')', '\"'] (~[')'])* (')')+)* '\"'
		|	'\"' \strWithCustomDelims{'\"'}
		);
	#FirstNameChar    = ['A'-'Z'] | ['a'-'z'] | ['_', '$'];
	#Digit            = ['0'-'9'];
	#HexDigit         = Digit | ['A'-'F'] | ['a'-'f'];
	#NumericLiteral   = '0' | ['1'-'9'] (Digit)*;
	#HexLiteral       = '0' ['X', 'x'] (HexDigit)+;
	#BaseFloatLiteral = (Digit)+ '.' (Digit)* | '.' (Digit)+;
	Assign            = '=';
	Colon             = ':';
	Comma             = ',';
	LBrace            = '{';
	LBracket          = '[';
	LPar              = '(';
	Period            = '.';
	RBrace            = '}';
	RBracket          = ']';
	RPar              = ')';
	Semicolon         = ';';

FillerTokens:
	SingleLineComment = "//" (~['\r', '\n'])* ["\r\n" | ['\r', '\n']];
	MultiLineComment  = "/*" (~['*'])* ('*')+ (~['*', '/'] (~['*'])* ('*')+)* '/';
	Whitespace        = (['\t', ' ', '\r', '\n'])+;

TokenSpecializations:
	KeyBool    = Name("bool"   );
	KeyDouble  = Name("double" );
	KeyFalse   = Name("false"  );
	KeyFloat   = Name("float"  );
	KeyInt     = Name("int"    );
	KeyLong    = Name("long"   );
	KeyString  = Name("string" );
	KeyStrings = Name("strings");
	KeyTrue    = Name("true"   );
	KeyRGB     = Name("rgb"    );
	KeyRGBA    = Name("rgba"   );
	KeyVec3    = Name("vec3"   );
	KeyVec4    = Name("vec4"   );

Rules:
Start = {
	(
		(
			Lookahead(AnyName LBrace) Scope
		|	Entry
		)
	)*
	EOF
}

AnyName = {
	#AnyNamePart (Period #AnyNamePart)*
}

#AnyNamePart = {
	Name | KeyBool | KeyDouble | KeyFalse | KeyFloat | KeyInt | KeyLong | KeyString | KeyStrings | KeyTrue | KeyRGB | KeyRGBA | KeyVec3 | KeyVec4
}

Scope = {
	AnyName LBrace
	(
		(
			Lookahead(AnyName LBrace) Scope
		|	Entry
		)
	)*
	RBrace
}

Entry = {
	(
		KeyBool                AnyName Assign (KeyTrue | KeyFalse)
	|	(KeyInt   | KeyLong  ) AnyName Assign IntLiteral
	|	(KeyFloat | KeyDouble) AnyName Assign (IntLiteral | FloatLiteral)
	|	KeyString              AnyName Assign StringLiteral
	|	(KeyVec3  | KeyRGB   ) AnyName Assign #Vec3
	|	KeyRGBA                AnyName Assign #Vec4
	|	KeyStrings LBracket (AnyName Colon StringLiteral)* RBracket
	)
	Semicolon
}

#Vec3 = {
	KeyVec3
	LPar  (IntLiteral | FloatLiteral)
	Comma (IntLiteral | FloatLiteral)
	Comma (IntLiteral | FloatLiteral) RPar
}

#Vec4 = {
	KeyVec4
	LPar  (IntLiteral | FloatLiteral)
	Comma (IntLiteral | FloatLiteral)
	Comma (IntLiteral | FloatLiteral)
	Comma (IntLiteral | FloatLiteral) RPar
}
